/**
 * Vector Store - 向量存储系统
 * 
 * 基于 IndexedDB 的轻量级向量存储实现
 * 使用余弦相似度进行向量搜索
 */

import type { DocumentChunk, SearchResult } from '@/types/knowledge';

/**
 * 向量存储配置
 */
export interface VectorStoreConfig {
  /** 数据库名称 */
  dbName: string;
  /** 向量维度 */
  dimension: number;
  /** 相似度阈值 (0-1) */
  similarityThreshold?: number;
}

/**
 * 向量条目
 */
interface VectorEntry {
  /** 块 ID */
  id: string;
  /** 文档 ID */
  documentId: string;
  /** 知识库 ID */
  knowledgeBaseId: string;
  /** 向量 */
  vector: number[];
  /** 块内容 */
  content: string;
  /** 元数据 */
  metadata: any;
  /** 创建时间 */
  createdAt: number;
}

/**
 * 向量存储类
 */
export class VectorStore {
  private config: VectorStoreConfig;
  private db: IDBDatabase | null = null;
  private readonly storeName = 'vectors';

  constructor(config: VectorStoreConfig) {
    this.config = {
      similarityThreshold: 0.7,
      ...config,
    };
  }

  /**
   * 初始化数据库
   */
  async initialize(): Promise<void> {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.config.dbName, 1);

      request.onerror = () => reject(request.error);
      request.onsuccess = () => {
        this.db = request.result;
        resolve();
      };

      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        
        // 创建向量存储
        if (!db.objectStoreNames.contains(this.storeName)) {
          const store = db.createObjectStore(this.storeName, { keyPath: 'id' });
          store.createIndex('documentId', 'documentId', { unique: false });
          store.createIndex('knowledgeBaseId', 'knowledgeBaseId', { unique: false });
          store.createIndex('createdAt', 'createdAt', { unique: false });
        }
      };
    });
  }

  /**
   * 添加向量
   */
  async addVector(
    chunk: DocumentChunk,
    vector: number[]
  ): Promise<void> {
    if (!this.db) {
      throw new Error('Database not initialized');
    }

    if (vector.length !== this.config.dimension) {
      throw new Error(
        `Vector dimension mismatch: expected ${this.config.dimension}, got ${vector.length}`
      );
    }

    const entry: VectorEntry = {
      id: chunk.id,
      documentId: chunk.documentId,
      knowledgeBaseId: chunk.knowledgeBaseId,
      vector,
      content: chunk.content,
      metadata: chunk.metadata,
      createdAt: Date.now(),
    };

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([this.storeName], 'readwrite');
      const store = transaction.objectStore(this.storeName);
      const request = store.put(entry);

      request.onerror = () => reject(request.error);
      request.onsuccess = () => resolve();
    });
  }

  /**
   * 批量添加向量
   */
  async addVectors(chunks: DocumentChunk[], vectors: number[][]): Promise<void> {
    if (chunks.length !== vectors.length) {
      throw new Error('Chunks and vectors length mismatch');
    }

    for (let i = 0; i < chunks.length; i++) {
      await this.addVector(chunks[i], vectors[i]);
    }
  }

  /**
   * 搜索相似向量
   */
  async search(
    queryVector: number[],
    topK: number = 5,
    knowledgeBaseId?: string
  ): Promise<SearchResult[]> {
    if (!this.db) {
      throw new Error('Database not initialized');
    }

    if (queryVector.length !== this.config.dimension) {
      throw new Error(
        `Query vector dimension mismatch: expected ${this.config.dimension}, got ${queryVector.length}`
      );
    }

    // 获取所有向量
    const entries = await this.getAllVectors(knowledgeBaseId);

    // 计算相似度并排序
    const results = entries
      .map((entry) => ({
        entry,
        similarity: this.cosineSimilarity(queryVector, entry.vector),
      }))
      .filter((result) => result.similarity >= (this.config.similarityThreshold || 0))
      .sort((a, b) => b.similarity - a.similarity)
      .slice(0, topK);

    // 转换为 SearchResult
    return results.map((result): SearchResult => ({
      chunkId: result.entry.id,
      documentId: result.entry.documentId,
      content: result.entry.content,
      score: result.similarity,
      metadata: result.entry.metadata,
    }));
  }

  /**
   * 获取所有向量
   */
  private async getAllVectors(knowledgeBaseId?: string): Promise<VectorEntry[]> {
    if (!this.db) {
      throw new Error('Database not initialized');
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([this.storeName], 'readonly');
      const store = transaction.objectStore(this.storeName);
      
      let request: IDBRequest;
      if (knowledgeBaseId) {
        const index = store.index('knowledgeBaseId');
        request = index.getAll(knowledgeBaseId);
      } else {
        request = store.getAll();
      }

      request.onerror = () => reject(request.error);
      request.onsuccess = () => resolve(request.result as VectorEntry[]);
    });
  }

  /**
   * 删除文档的所有向量
   */
  async deleteByDocumentId(documentId: string): Promise<void> {
    if (!this.db) {
      throw new Error('Database not initialized');
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([this.storeName], 'readwrite');
      const store = transaction.objectStore(this.storeName);
      const index = store.index('documentId');
      const request = index.openCursor(IDBKeyRange.only(documentId));

      request.onerror = () => reject(request.error);
      request.onsuccess = (event) => {
        const cursor = (event.target as IDBRequest).result;
        if (cursor) {
          cursor.delete();
          cursor.continue();
        } else {
          resolve();
        }
      };
    });
  }

  /**
   * 删除知识库的所有向量
   */
  async deleteByKnowledgeBaseId(knowledgeBaseId: string): Promise<void> {
    if (!this.db) {
      throw new Error('Database not initialized');
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([this.storeName], 'readwrite');
      const store = transaction.objectStore(this.storeName);
      const index = store.index('knowledgeBaseId');
      const request = index.openCursor(IDBKeyRange.only(knowledgeBaseId));

      request.onerror = () => reject(request.error);
      request.onsuccess = (event) => {
        const cursor = (event.target as IDBRequest).result;
        if (cursor) {
          cursor.delete();
          cursor.continue();
        } else {
          resolve();
        }
      };
    });
  }

  /**
   * 清空所有向量
   */
  async clear(): Promise<void> {
    if (!this.db) {
      throw new Error('Database not initialized');
    }

    return new Promise((resolve, reject) => {
      const transaction = this.db!.transaction([this.storeName], 'readwrite');
      const store = transaction.objectStore(this.storeName);
      const request = store.clear();

      request.onerror = () => reject(request.error);
      request.onsuccess = () => resolve();
    });
  }

  /**
   * 获取向量数量统计
   */
  async getStats(knowledgeBaseId?: string): Promise<{
    totalVectors: number;
    dimension: number;
  }> {
    const entries = await this.getAllVectors(knowledgeBaseId);
    return {
      totalVectors: entries.length,
      dimension: this.config.dimension,
    };
  }

  /**
   * 计算余弦相似度
   */
  private cosineSimilarity(a: number[], b: number[]): number {
    if (a.length !== b.length) {
      throw new Error('Vectors must have the same dimension');
    }

    let dotProduct = 0;
    let normA = 0;
    let normB = 0;

    for (let i = 0; i < a.length; i++) {
      dotProduct += a[i] * b[i];
      normA += a[i] * a[i];
      normB += b[i] * b[i];
    }

    normA = Math.sqrt(normA);
    normB = Math.sqrt(normB);

    if (normA === 0 || normB === 0) {
      return 0;
    }

    return dotProduct / (normA * normB);
  }

  /**
   * 关闭数据库
   */
  close(): void {
    if (this.db) {
      this.db.close();
      this.db = null;
    }
  }
}

/**
 * 创建向量存储实例
 */
export function createVectorStore(config: VectorStoreConfig): VectorStore {
  return new VectorStore(config);
}

